﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.IO;

using dotUML.Core;
using dotUML.Core.Common;

namespace dotUML.Client.ConsoleClient
{
    class Program
    {
        /// <summary>
        /// String used for identify the input options
        /// </summary>
        private const string ComponentOption = "-component";
        private const string SequenceOption = "-sequence";
        private const string UsecaseOption = "-usecase";

        /// <summary>
        ///  Enumerator with the console input option
        /// </summary>
        private enum Options
        {
            Component,
            Sequence,
            Usecase,
            Invalid
        }

        /// <summary>
        /// The main entry point for the dotUML console application.
        /// </summary>
        /// <param name="args">Command line arguments.</param>
        [STAThread]
        static void Main(string[] args)
        {
            IDiagramEngine engine = DiagramEngineFactory.GetDiagramEngine();
                        
            if( !ValidateInput(args) )                          
                OutputHelp();
            else
            {
                string xmlFile;
                string outputPath;                

                // Control if there are 3 parameters 
                // in this case the first one is an option 
                // parameter.
                if (args.Length == 3)
                {
                    xmlFile = args[1];
                    outputPath = args[2];
                }
                else
                {
                    xmlFile = args[0];
                    outputPath = args[1];
                }

                string xmlContent = LoadXml(xmlFile);

                if (!engine.Validate(xmlContent))
                    OutputErrors(engine.Errors);
                else
                {
                    // File xml is processed
                    List<byte[]> images = engine.Process(xmlContent);

                    if(!engine.Errors.Equals(null))
                        OutputErrors(engine.Errors);
                    else
                        /// TODO specify correct file name and select correct image
                        SaveFile(outputPath, xmlFile, images[0]);
                }
            }
        }

        /// <summary>
        /// Validate command line input.
        /// </summary>
        /// <param name="args">Command line arguments.</param>
        /// <returns>True if arguments are correct, otherwise false.</returns>
        static bool ValidateInput(string[] args)
        {
            // too few arguments
            if (args.Length < 2)
                return false;
            else
            {
                bool thereIsAnOption = false;

                // validate input option
                if ( args.Length == 3 )
                {
                    // validate option value
                    if ( args[0].StartsWith( "-" ) )
                        // TODO memorize the option
                        thereIsAnOption = ValidateOption(args[0]) != Options.Invalid;                    
                    else
                        return false;
                }

                string xmlFile;
                string outputPath;

                if ( thereIsAnOption )
                {
                    xmlFile = args[1];
                    outputPath = args[2];
                }
                else
                {
                    xmlFile = args[0];
                    outputPath = args[1];
                }

                // the input is validate if exists the file and the output path
                return ( File.Exists( xmlFile ) ) && ( Directory.Exists( outputPath ) );
            }                
        }

         /// <summary>
        /// Validate input option.
        /// </summary>
        /// <param name="args">Option specified in command line arguments.</param>
        /// <returns>True if option is correct, otherwise false.</returns>
        static Options ValidateOption(string option)
        {
            switch (option)
            {
                case ComponentOption:
                    return Options.Component;                    
                case SequenceOption:
                    return Options.Sequence;                   
                case UsecaseOption:
                    return Options.Usecase;       
                default:
                    return Options.Invalid;
            }           
        }
        /// <summary>
        /// Output instructions on how to use the dotUML console 
        /// application to the console.
        /// </summary>
        static void OutputHelp()
        {
            Console.WriteLine("Usage: dotUML [-options] xmlFile xmlOutputPath");
            Console.WriteLine("\t(to parse an xml File)");
            Console.WriteLine("\twhere options include:");
            Console.WriteLine("\t\t-sequence          xmlFile represents a UML sequence diagram");
            Console.WriteLine("\t\t-usecase           xmlFile represents a UML use case diagram");
            Console.WriteLine("\t\t-component         xmlFile represents a UML component diagram");
        }

        /// <summary>
        /// Load an xml-file from a specified location.
        /// </summary>
        /// <param name="XmlPath">Xml-file path.</param>
        /// <returns>Xml-file in text representation.</returns>
        static string LoadXml(string XmlPath)
        {
            // The stream is created read and closed
            StreamReader streamReader = new StreamReader(XmlPath);

            string text = streamReader.ReadToEnd();

            streamReader.Close();

            return text;
        }

        /// <summary>
        /// Process an xml-file.
        /// </summary>
        /// <param name="Xml">String representation of the xml-file.</param>
        static void ProcessXml(string Xml)
        {
        }

        /// <summary>
        /// Save an output file.
        /// </summary>
        /// <param name="OutputPath">Output folder.</param>
        /// <param name="FileName">Output file name.</param>
        /// <param name="Data">Diagram image in the binary representation.</param>
        static void SaveFile(string OutputPath, string FileName, byte[] Data)
        {
            // The stream is created written and closed
            StreamWriter saveWriter = new StreamWriter(OutputPath + FileName);

            saveWriter.Write(Data);
            
            saveWriter.Close();
        }

        /// <summary>
        /// Output error messages to the console.
        /// </summary>
        /// <param name="Errors">Error messages.</param>
        static void OutputErrors(List<IError> Errors)
        {
            foreach (IError error in Errors)
            {
                Console.WriteLine(error.ErrorMessage);
            }
        }      
    }
}
